package cn.rokhdelar.umbrsapi.oss.service;

import cn.rokhdelar.umbrsapi.oss.config.OSSConfig;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class OSSService {
    private final MinioClient minioClient;
    private final OSSConfig ossConfig;

    public OSSService(MinioClient minioClient, OSSConfig ossConfig) {
        this.minioClient = minioClient;
        this.ossConfig = ossConfig;
    }

    /**
     * 判断指定的bucket是否存在
     * @param bucketName bucket名称
     * @return 是否存在
     */
    @SneakyThrows
    public Boolean bucketExists(String bucketName) {
        return minioClient.bucketExists(
                BucketExistsArgs.builder().bucket(bucketName).build()
        );
    }

    /**
     * 创建指定名称的bucket
     * @param bucketName bucket名称
     */
    @SneakyThrows
    public void makeBucket(String bucketName) {
        if (!bucketExists(bucketName)) return;
        minioClient.makeBucket(
                MakeBucketArgs.builder().bucket(bucketName).build()
        );
    }

    /**
     * 列出所有的Bucket
     * @return bucket列表
     */
    @SneakyThrows
    public List<Bucket> listBuckets() {
        return minioClient.listBuckets();
    }

    /**
     * 删除bucket，bucket为空才能删除，否则失败
     * @param bucketName 要删除的bucket名称
     * @return 是否成功
     */
    @SneakyThrows
    public Boolean removeBucket(String bucketName) {
        if(!bucketExists(bucketName)) {
            return false;
        }
        Iterable<Result<Item>> results = listObjects(bucketName);
        for(Result<Item> result: results) {
            Item item = result.get();
            if(item.size() > 0){
                // bucket里面还有对象文件，不能删除
                return Boolean.FALSE;
            }
        }
        minioClient.removeBucket(
                RemoveBucketArgs.builder().bucket(bucketName).build()
        );
        if (!bucketExists(bucketName)) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    /**
     * 列出bucket中的所有文件
     * @param bucketName bucket名称
     * @return object集合
     */
    @SneakyThrows
    public Iterable<Result<Item>> listObjects(String bucketName) {
        if (!bucketExists(bucketName)) {
            return null;
        }
        return minioClient.listObjects(
                ListObjectsArgs.builder().bucket(bucketName).build()
        );
    }

    /**
     * 存入object
     * @param multipartFile 上传文件
     * @param bucketName bucket名称
     * @return 访问路径
     */
    @SneakyThrows
    public String putObject(MultipartFile multipartFile, String bucketName) {
        bucketName = StringUtils.isNotBlank(bucketName) ? bucketName: ossConfig.getBucketName();
        if (!bucketExists(bucketName)) {
            return null;
        }

        if (!bucketExists(bucketName)) {
            makeBucket(bucketName);
        }
        String fileName = multipartFile.getOriginalFilename();
        assert fileName != null;
        String objectName = UUID.randomUUID().toString().replaceAll("-", "")
                + fileName.substring(fileName.lastIndexOf("."));
        ByteArrayInputStream inputStream = new ByteArrayInputStream(multipartFile.getBytes());
        minioClient.putObject(
                PutObjectArgs.builder()
                        .bucket(bucketName)
                        .object(objectName)
                        .stream(inputStream, -1, ossConfig.getMaxImageSize())
                .build());
        return ossConfig.getEndpoint() + "/" + bucketName + "/" + objectName;
    }

    /**
     * 下载object
     * @param bucketName bucket名称
     * @param objectName object名称
     * @return input stream
     */
    @SneakyThrows
    public InputStream downloadObject(String bucketName, String objectName) {
        if (!bucketExists(bucketName)) {
            return null;
        }
        return minioClient.getObject(
                GetObjectArgs.builder().bucket(bucketName).object(objectName).build()
        );
    }

    /**
     * 删除object
     * @param bucketName bucket名称
     * @param objectName object名称
     * @return 是否删除成功
     */
    @SneakyThrows
    public Boolean removeObject(String bucketName, String objectName) {
        if (!bucketExists(bucketName)) {
            return Boolean.FALSE;
        }
        minioClient.removeObject(
                RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()
        );
        return Boolean.TRUE;
    }

    /**
     * 获取object url
     * @param bucketName bucket名称
     * @param objectName object名称
     * @return url
     */
    @SneakyThrows
    public String getObjectUrl(String bucketName, String objectName) {
        if (!bucketExists(bucketName)) {
            return null;
        }
        return minioClient.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                        .method(Method.GET)
                        .bucket(bucketName)
                        .object(objectName)
                        .expiry(2, TimeUnit.DAYS)
                        .build()
        );
    }
}
